#include "stdafx.h"
#include "kernel.h"


namespace xm
{
	static LPSTR builtin_search_path [] = 
	{
		"?:\\windows\\",
		"?:\\windows\\system32\\",
		"?:\\",
	};

	enum { builtin_search_path_num = sizeof(builtin_search_path)/sizeof(builtin_search_path[0]) };

	static LPCSTR builtin_search_ext [] = 
	{
		NULL, ".dll", ".exe", ".bat", ".com", ".scr"
	};

	enum { builtin_search_ext_num = sizeof(builtin_search_ext)/sizeof(builtin_search_ext[0]) };

	static long init_search_path( char os_drive )
	{
		for( size_t i = 0; i < builtin_search_path_num; ++ i )
		{
			builtin_search_path[i][0] = os_drive;
		}
	}


	kernel_t::kernel_t( ntcore_t & ofs_ ) : _clientid(0), ntk(ofs_)
	{
	}
	uint32_t	kernel_t::client_id_alloc()
	{
		return (_clientid += 4);
	}

	void		kernel_t::client_id_free( uint32_t id )
	{
		return ;
	}

	optr<thread_t>	kernel_t::thread_create( process_t* proc, vxvma_t addr, size_t stack_size, size_t opts /* = TOPT_USER_THREAD */, vxvma_t stackbase /* = 0 */ )
	{
		if( !proc ) return 0;

		thstate ths = (opts & TOPT_SUSPEND) ? (ThreadSuspend) : (ThreadReady);

		optr<thread_t> to = new thread_t( proc );
		RASSERT( to, NULL );

		RFAILED_( to->create( addr, stack_size, ths, stackbase ), NULL );

		if( opts & TOPT_USER_THREAD )
		{
			RFAILED_( to->init_user_thread(opts), NULL );
			_thread_map[to->tid] = to;
			_thread_list.link_back(to);
			if( !proc->mainthread ) 
				proc->mainthread = to;
		}

		return to;
	}

	void kernel_t::thread_clear()
	{
		_thread_map.clear();
	}

	thread_t * kernel_t::thread_find_by_state( thread_t* from, thstate state, bool noself )
	{
		thread_t * endto, * scan;
		if( from )
		{
			endto = from;
			scan = endto->next();
		}
		else
		{
			scan = _thread_list.first();
			endto = scan->prev();
			noself = false;
		}
		for( ; scan != endto; scan = scan->next() )
		{
			if( scan->status == state )
				return scan;
		}
		if( !noself )
		{
			if( scan->status == state )
				return scan;
		}
		return 0;
	}


	thread_t* kernel_t::thread_switch( bool noself )
	{
		thread_t * next_thread = thread_find_by_state( _current_thread, ThreadReady, noself );
		long lr = thread_select( next_thread );
		if( lr < 0 ) return NULL;
		return next_thread;
	}

	long kernel_t::thread_erase( thread_t * to )
	{
		to->status = ThreadDead;
		if( to == _current_thread ) thread_switch(true);
		_thread_list.unlink(to);
		_thread_map.erase(to->tid);
		return 0;
	}

	process_t * kernel_t::process_create( process_t * parent, uint32_t opt )
	{
		optr<process_t> po = new process_t( *this );
		if( !po ) return NULL;
		long lr = po->init(parent, opt);
		if( lr < 0 ) return NULL;
		po->pid = client_id_alloc();
		_process_map[po->pid] = po;
		return po;
	}

	kop_t kernel_t::w32_search_find_path( LPCSTR curdir, LPCSTR name, size_t opt )
	{
		w32_path_t w32p;
		
		rpr_t r = ntk.resolve_path_win32( name, w32p );
		if( r < 0 ) return NULL;
		
		if( r != NS_WIN32_UNK )
			return ntk.find_path( w32p, opt );

		kop_t kop ;
		std::string testpath;
		if( curdir )
		{
			testpath = curdir;
			testpath.push_back( '\\' );
			testpath.append( name );
			kop = ntk.find_path( testpath.c_str(), opt|OFS_WIN32_PATH );
			if( kop ) return kop;
		}
		for( size_t j = 0; j < builtin_search_ext_num; ++ j )
		{
			LPCSTR ext = builtin_search_ext[j];
			for( size_t i = 0; i < builtin_search_path_num; ++ i )
			{
				testpath = builtin_search_path[i];
				testpath.push_back( '\\' );
				testpath.append( name );
				if( ext ) testpath.append( ext );
				testpath[0] = ntk.os_drive()[0];
				kop = ntk.find_path( testpath.c_str(), opt|OFS_WIN32_PATH );
				if( kop ) return kop;
			}
		}
		return NULL;
	}

	long kernel_t::thread_select( thread_t * to )
	{
		optr<thread_t> now_thread = _current_thread;
		if( now_thread == to ) return S_FALSE;
		_current_thread.dispose();

		process_t * new_proc, *old_proc;
		new_proc = to ? to->proc : 0;
		old_proc = now_thread ? now_thread->proc : 0;

		if( now_thread ) 
			now_thread->cpu_to_context();

		if( old_proc != new_proc )
		{
			if( old_proc ) old_proc->uninstall();
			if( new_proc ) new_proc->install();
		}

		_current_thread = to;
		if( new_proc ) new_proc->nowthread = to;
		if( old_proc ) old_proc->nowthread = 0;
		//////////////////////////////////////////////////////////////////////////
		return S_OK;
	}

	void kernel_t::process_init_peb32( PEB32 * peb )
	{
		peb->OSMajorVersion = 6;
		peb->OSMinorVersion = 0;
		peb->SessionId = 2;
		peb->BeingDebugged = 0;
		peb->NumberOfProcessors = 1;
		peb->NumberOfHeaps = 1;
		peb->MaximumNumberOfHeaps = 100;
		peb->MinimumStackCommit = VM_PAGE_SIZE;
	}
	void kernel_t::process_init_peb64( PEB64 * peb )
	{
		peb->OSMajorVersion = 6;
		peb->OSMinorVersion = 0;
		peb->SessionId = 2;
		peb->BeingDebugged = 0;
		peb->NumberOfProcessors = 1;
		peb->NumberOfHeaps = 1;
		peb->MaximumNumberOfHeaps = 100;
		peb->MinimumStackCommit = VM_PAGE_SIZE;
	}

};


